概述
ReentrantLock 顾名思义就是可重入锁,即当前持有该锁的线程能够多次获取该锁,无需等待。
ReentrantLock 和 synchronized 的区别
相同点
- 都是可重入锁
不同点
synchronized是依赖于JVM实现的,而ReenTrantLock是JDK实现的synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,或者在加锁的代码块内由于程序异常退出而没有释放锁造成死锁,所以最好在finally中声明释放锁。ReenTrantLock可以指定是公平锁还是非公平锁。而synchronized只能是非公平锁。所谓的公平锁就是先等待的线程先获得锁。ReenTrantLock提供了一个Condition(条件)类,用来实现分组唤醒需要唤醒的线程们,而不是像synchronized要么随机唤醒一个线程要么唤醒全部线程。一个Condition对象的signal(signalAll)方法和该对象的await方法是一一对应的,也就是一个Condition对象的signal(signalAll)方法不能唤醒其他Condition对象的await方法。ReenTrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。
Condition 和 Object的wait和notify/notifyAll 的区别
类似点
Condition对象的awiat方法和Object对象的wait方法等效。调用时也必须获得锁。Condition对象的signal方法和Object对象的notify方法等效。调用时也必须获得锁。Condition对象的signalAll方法和Object对象的notifyAll方法等效。调用时也必须获得锁。
不同点
- Condition能够支持多个等待队列(new 多个Condition对象),而Object方式只能支持一个
使用方法
ReentrantLock(boolean fair) 可以根据传入的参数来创建两种不同的锁:
- new ReentrantLock(true):公平锁,线程获取锁的顺序是按照加锁顺序来的
- new ReentrantLock(false):非公平锁,抢锁机制,先lock的线程不一定先获得锁。
1 | private ReentrantLock mLock = new ReentrantLock(); |
1 | 17:16:01.072 E/Test: Thread1 start |
配合 Condition 使用:
1 | private ReentrantLock mLock = new ReentrantLock(true); |
1 | 17:27:52.250 E/Test: Thread1 start |
从这里可以看出,只调用 condition1.signalAll() 后,Thread3 后面没有被唤醒。
下面来看一下在 Thread4 中调用 condition2.signalAll() 的执行情况。
1 | Log.e("Test", Thread.currentThread().getName() + " condition1.signalAll()"); |
1 | 17:36:23.026 E/Test: Thread1 start |
Thread3 被唤醒,得到锁后得以继续执行。